package com.dobbinsoft.iotechn.device.mqtt.handler;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.dobbinsoft.iotechn.core.exception.ServiceException;
import com.dobbinsoft.iotechn.data.compent.CacheComponent;
import com.dobbinsoft.iotechn.device.api.biz.DeviceBizService;
import com.dobbinsoft.iotechn.device.constant.DeviceConst;
import com.dobbinsoft.iotechn.device.domain.DeviceDO;
import com.dobbinsoft.iotechn.device.domain.ProductDataDO;
import com.dobbinsoft.iotechn.device.entity.DeviceSessionEntity;
import com.dobbinsoft.iotechn.device.enums.DeviceStatusType;
import com.dobbinsoft.iotechn.device.enums.IotMessageResultType;
import com.dobbinsoft.iotechn.device.enums.IotMessageType;
import com.dobbinsoft.iotechn.device.mapper.DeviceMapper;
import com.dobbinsoft.iotechn.device.mapper.ProductDataMapper;
import com.dobbinsoft.iotechn.device.mqtt.message.IotDeviceConnectMessage;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Description:
 * User: rize
 * Date: 2020/6/22
 * Time: 15:18
 */
public class IotMqttConnectMessageHandler implements IotMqttMessageHandler<IotDeviceConnectMessage> {

    @Autowired
    private DeviceMapper deviceMapper;

    @Autowired
    private ProductDataMapper productDataMapper;

    @Autowired
    private DeviceBizService deviceBizService;

    @Autowired
    private CacheComponent cacheComponent;

    @Override
    public int handle(String accessKeyId, IotDeviceConnectMessage msg) {
        // 去设备Hash表中获取设备
        DeviceSessionEntity deviceSessionEntity = cacheComponent.getHashObj(DeviceConst.CA_DEVICE_HASH, accessKeyId, DeviceSessionEntity.class);
        if (deviceSessionEntity == null) {
            deviceSessionEntity = new DeviceSessionEntity();
            DeviceDO deviceDO = deviceMapper.selectOne(new QueryWrapper<DeviceDO>().eq("access_key_id", accessKeyId));
            if (deviceDO == null) {
                return IotMessageResultType.ERROR_FATAL.getCode();
            }
            BeanUtils.copyProperties(deviceDO, deviceSessionEntity);
        }
        try {
            if (deviceSessionEntity.getStatus().intValue() == DeviceStatusType.INACTIVE.getCode()) {
                // 激活设备。
                deviceBizService.activeDevice(deviceSessionEntity.getId(), deviceSessionEntity.getProductId());
                this.updateCache(deviceSessionEntity, DeviceStatusType.ONLINE.getCode());
                // 在此处更新缓存中设备状态
                return IotMessageResultType.SUCCESS.getCode();
            } else if (deviceSessionEntity.getStatus().intValue() == DeviceStatusType.OFFLINE.getCode()) {
                deviceBizService.onlineDevice(deviceSessionEntity.getId());
                this.updateCache(deviceSessionEntity, DeviceStatusType.ONLINE.getCode());
                return IotMessageResultType.SUCCESS.getCode();
            } else if (deviceSessionEntity.getStatus().intValue() == DeviceStatusType.SCRAP.getCode()) {
                return IotMessageResultType.ERROR_FATAL.getCode();
            } else {
                // 有可能是重连，直接空过
                return IotMessageResultType.SUCCESS.getCode();
            }
        } catch (ServiceException e) {
            return IotMessageResultType.ERROR_FATAL.getCode();
        }
    }

    private void updateCache(DeviceSessionEntity sessionEntity, Integer status) {
        // 更新设备缓存
        // 1. 更新状态
        sessionEntity.setCredit(10);
        sessionEntity.setStatus(status);
        // 2. 封装数据点
        List<ProductDataDO> list = productDataMapper.selectList(new QueryWrapper<ProductDataDO>().eq("product_id", sessionEntity.getProductId()));
        Map<String, ProductDataDO> map = list.stream().collect(Collectors.toMap(ProductDataDO::getIdTag, item -> item));
        sessionEntity.setProductDataMap(map);
        cacheComponent.putHashObj(DeviceConst.CA_DEVICE_HASH, sessionEntity.getAccessKeyId(), sessionEntity);
    }

    @Override
    public int getCode() {
        return IotMessageType.CONNECT.getCode();
    }

    @Override
    public Class<IotDeviceConnectMessage> getMessageType() {
        return IotDeviceConnectMessage.class;
    }
}
